package admin

import (
	"context"
	"database/sql"
	"fmt"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
	"miaoyu/internal/dao"
	"miaoyu/internal/enums/menuenum"
	"miaoyu/internal/enums/roleenum"
	"miaoyu/internal/model/admin"
	"miaoyu/internal/model/entity"
	"miaoyu/internal/service"
)

func init() {
	service.RegisterMenu(NewMenu())
}

type sMenu struct {
}

func NewMenu() *sMenu {
	return &sMenu{}
}

func (s *sMenu) GetAllList(ctx context.Context, where g.MapStrAny) (res []entity.MyMenu, resErr error) {
	res, resErr = dao.MyMenu.GetAllList(ctx, where)

	return
}

// GetAllEnableList 获取所有可用菜单列表
func (s *sMenu) GetAllEnableList(ctx context.Context, where g.MapStrAny) (res []entity.MyMenu, resErr error) {
	if where != nil {
		where["status"] = menuenum.Enable
	} else {
		where = g.MapStrAny{"status": menuenum.Enable}
	}
	res, resErr = dao.MyMenu.GetAllList(ctx, where)

	return
}

// GetAdminMenuList 初始化获取用户所有目录菜单类型
func (s *sMenu) GetAdminMenuList(ctx context.Context) (res []entity.MyMenu, err error) {
	var (
		menuList []entity.MyMenu
		menuErr  error
	)
	user := service.Session().GetUser(ctx)

	//超级管理员渠道
	if user.IsAdmin {
		menuList, menuErr = dao.MyMenu.GetMenuList(ctx, g.MapStrAny{"hidden": menuenum.Enable})
		if menuErr != nil {
			err = menuErr
			fmt.Println("获取菜单信息失败")
			return
		}
		res = menuList
		return
	}

	roleList, roleErr := dao.MyUserRole.GetRoleListByUserId(ctx, user.Id, roleenum.AbilityRole)
	if roleErr != nil {
		err = roleErr
		return
	}
	menuList, menuErr = dao.MyRoleMenu.GetMenuListByRole(ctx, g.MapStrAny{"r.role_id IN (?)": roleList, "m.hidden": menuenum.Enable})
	if menuErr != nil {
		err = menuErr
		return
	}
	res = menuList

	return
}

/*
GetMenuListJoinRole
获取带有某个角色标识的权限
*/
func (s *sMenu) GetMenuListJoinRole(ctx context.Context, roleId int64) (res []admin.MenuWithRoleOutput, resErr error) {

	menuList, menuErr := s.GetAllList(ctx, g.MapStrAny{})
	if menuErr != nil && menuErr != sql.ErrNoRows {
		resErr = menuErr
	}
	roleMenuList, roleErr := dao.MyRoleMenu.GetAllListWithRole(ctx, roleId)
	if roleErr != nil && roleErr != sql.ErrNoRows {
		resErr = roleErr
	}

	for _, v := range menuList {
		var tmp admin.MenuWithRoleOutput
		gconv.Scan(v, &tmp)
		tmp.Open = true
		if v.State == gconv.Int(menuenum.Disable) {
			tmp.ChkDisabled = true
		} else {
			tmp.ChkDisabled = false
		}
		for _, vv := range roleMenuList {

			if v.Id == vv.MenuId {
				tmp.Checked = true

				break
			} else {
				tmp.Checked = false
			}
		}

		res = append(res, tmp)
	}
	return
}

// GetMenuList  获取菜单类型列表
func (s *sMenu) GetMenuList(ctx context.Context, where g.MapStrAny) (res []entity.MyMenu, resErr error) {
	res, resErr = dao.MyMenu.GetMenuList(ctx, nil)
	if resErr != nil {
		return
	}
	//归类排序
	return
}
func (s *sMenu) GetMenuById(ctx context.Context, id int64) (res entity.MyMenu, resErr error) {
	res, resErr = dao.MyMenu.GetMenuById(ctx, id)
	if resErr != nil && resErr != sql.ErrNoRows {
		resErr = gerror.New("检索错误")
		return
	}
	if resErr == sql.ErrNoRows {
		resErr = gerror.NewSkip(404, "数据不存在")
		return
	}
	return
}
func (s *sMenu) CheckMenuSubmit(ctx context.Context, menu admin.MenuInput, editId int64) (err error) {
	//如果父类菜单为目录类型，则父类菜单值必须为-1
	if menu.MenuType == gconv.Int(menuenum.CateGory) && menu.ParentId != gconv.Int64(menuenum.RootMenu) {
		err = gerror.New("目录类型菜单父类菜单必须为根目录！")
		return
	}

	//如果不是目录类型，需要检查父类菜单是否是节点类型，节点类型下面没有子节点
	if menu.MenuType != gconv.Int(menuenum.CateGory) {
		if menu.ParentId == gconv.Int64(menuenum.RootMenu) {
			err = gerror.New("菜单类型为菜单的父节点不能为根目录")
			return
		}
		parentMenu, resErr := s.GetMenuById(ctx, menu.ParentId)
		if resErr != nil && resErr != sql.ErrNoRows {
			err = gerror.New("检索错误")
			return
		}
		if resErr == sql.ErrNoRows {
			err = gerror.NewSkip(404, "父类菜单不存在！")
			return
		}
		if parentMenu.MenuType == gconv.Int(menuenum.Node) {
			err = gerror.New("父类菜单不能为" + menuenum.Node.StringMenuType() + "类型！")
			return
		}
	}
	uniRes, uniErr := dao.MyMenu.GetMenu(ctx, g.MapStrAny{
		"uniname": menu.Uniname,
	})
	if uniErr == nil && uniRes.Id != editId {
		err = gerror.New("请检查路由名称是否重复！")
		return
	}

	//检查菜单链接是否重复
	if menu.Path != "#" {
		menuRes, resErr := dao.MyMenu.GetMenu(ctx, g.MapStrAny{
			"path":       menu.Path,
			"path_param": menu.PathParam,
		})
		if resErr != nil && resErr != sql.ErrNoRows {
			err = gerror.New("检索错误！")
			return
		}
		if resErr == sql.ErrNoRows {
			return
		}
		if menuRes.Id != editId {
			err = gerror.New("该链接已存在")
			return
		}
	}
	return
}
func (s *sMenu) Edit(ctx context.Context, menu admin.MenuInput, menuId int64) (res sql.Result, err error) {
	checkErr := s.CheckMenuSubmit(ctx, menu, menuId)
	if checkErr != nil {
		err = checkErr
		return
	}
	res, err = dao.MyMenu.UpdateMenuById(ctx, menu, menuId)

	if err != nil {
		return
	}

	return

}
func (s *sMenu) Add(ctx context.Context, menu admin.MenuInput) (h sql.Result, err error) {
	checkErr := s.CheckMenuSubmit(ctx, menu, -1)
	if checkErr != nil {
		err = checkErr
		return
	}
	h, err = dao.MyMenu.Add(ctx, menu)

	if err != nil {
		return
	}

	return

}
func (s *sMenu) Del(ctx context.Context, menuIds []int64) (sqlAffectRows int64, err error) {
	if len(menuIds) != 1 {
		err = gerror.New("每次只能删除一个菜单，请确定要删除的菜单！")
		return
	}
	menuId := menuIds[0]
	//检查该菜单是否含有字节点
	_, resErr := dao.MyMenu.GetMenu(ctx, g.MapStrAny{"parent_id": menuId})
	if resErr != nil && resErr != sql.ErrNoRows {
		err = gerror.New("检索错误！")
		return
	}
	if resErr != sql.ErrNoRows {
		err = gerror.New("请先删除该菜单子节点后再删除该该菜单")
		return
	}
	sqlAffectRows, err = dao.MyMenu.DeleteMenuById(ctx, menuId)
	if err != nil {
		err = gerror.NewSkip(404, "菜单删除失败")
		return
	}
	if sqlAffectRows == 0 {
		err = gerror.New("请求的信息不存在")
		return
	}

	return
}
